package tv.geir.slackspace.code;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Subclass of <code>ObjectInputStream</code> that uses a specified classloader
 * to resolve unresolved classes during deserialization. Before this instances
 * of this class can be used to deserialize objects, a classloader must have 
 * been set. Use <code>setClassLoader()</code> to set a classloader.
 * 
 * @author Geir Gullestad Pettersen
 *
 */
public class ClassLoadingObjectInputStream extends ObjectInputStream {
	
	/** Logger for this class */
	private static Log log = LogFactory.getLog(ClassLoadingObjectInputStream.class);

	/** Classloader used to resolve classes during deserialization */
	private ClassLoader classLoader;

	/**
	 * @param classLoader classloader to resolve unresolved classes
	 * @param inputstream the inputstream to read objects from
	 * @throws IOException
	 */
	public ClassLoadingObjectInputStream(ClassLoader cl, InputStream is)
			throws IOException {
		super(is);
		this.classLoader = cl;
	}

	@Override
	/**
	 * Resolves unresolved classes using <code>MobileClassLoader</code>
	 */
	protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
			ClassNotFoundException {
		if( classLoader == null ) {
			throw new NullPointerException( "ClassLoader has not yet been set" );
		}
		if( log.isDebugEnabled() ) {
			log.debug( "resolving " + desc );
		}
		return classLoader.loadClass(desc.getName());
	}
	
	/** Set a classloader for this object. The classloader will be used to
	 * resolve classes during deserialization.
	 * @param cl
	 */
	public void setClassLoader( ClassLoader cl ) {
		this.classLoader = cl;
	}
}
